# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher.
# This patch includes the following deltas:
#	           ChangeSet	1.1069.45.1 -> 1.1069.45.2
#	include/linux/hugetlb.h	1.2     -> 1.3    
#	arch/ia64/mm/hugetlbpage.c	1.3     -> 1.4    
#	fs/hugetlbfs/inode.c	1.4     -> 1.5    
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 03/09/30	khalid@fc.hp.com	1.1069.44.2
# ia64: do_settimeofday: fix compensation for lost ticks
# --------------------------------------------
# 03/09/30	davidm@tiger.hpl.hp.com	1.1069.44.3
# ia64: Mark access_ok() as likely to succeed (as is done in x86 tree).
# --------------------------------------------
# 03/09/30	len.brown@intel.com	1.1063.44.17
# [ACPI] acpi4asus-0.24a-0.25-2.4 (Karol Kozimor)
# --------------------------------------------
# 03/09/30	len.brown@intel.com	1.1063.44.18
# [ACPI] acpi4asus-0.25-0.26 (Karol Kozimor)
# --------------------------------------------
# 03/09/30	len.brown@intel.com	1.1069.1.71
# Merge intel.com:/home/lenb/bk/linux-acpi-test-2.4.22
# into intel.com:/home/lenb/bk/linux-acpi-test-2.4.23
# --------------------------------------------
# 03/09/30	stern@rowland.harvard.edu	1.1069.33.19
# [PATCH] USB: unusual_devs.h update
# --------------------------------------------
# 03/09/30	kaos@sgi.com	1.1069.44.4
# ia64: mca_asm.h documentation fixes
# 
# Documentation fix for mca_asm.h.  Refer to the released Intel manual
# and correct a field name.  No functional changes.
# --------------------------------------------
# 03/09/30	kenneth.w.chen@intel.com	1.1069.45.2
# HUGETLBFS: quota bugfix and sync to 2.6.
# 
# Here is a bug fix patch relative to latest Bjorn's 2.4 ia64 kernel tree.
# Mainly sync up hugetlbfs code w.r.t latest 2.6.
# 
# Hugetlb file system quota was incorrectly taken on every mmap even for
# the case that huge pages has been already allocated on the file inode.
# This results in taxing the same hugepage multiple times and causing mmap
# to fail on existing file when quota mistakenly runs out. This patch also
# fixes file size to account holes.
# --------------------------------------------
#
diff -Nru a/arch/ia64/mm/hugetlbpage.c b/arch/ia64/mm/hugetlbpage.c
--- a/arch/ia64/mm/hugetlbpage.c	Thu Oct  9 15:20:21 2003
+++ b/arch/ia64/mm/hugetlbpage.c	Thu Oct  9 15:20:21 2003
@@ -262,18 +262,19 @@
 			+ (vma->vm_pgoff >> (HPAGE_SHIFT - PAGE_SHIFT));
 		page = find_get_page(mapping, idx);
 		if (!page) {
-			loff_t i_size;
+			/* charge the fs quota first */
+			if (hugetlb_get_quota(mapping)) {
+				ret = -ENOMEM;
+				goto out;
+			}
 			page = alloc_hugetlb_page();
 			if (!page) {
+				hugetlb_put_quota(mapping);
 				ret = -ENOMEM;
 				goto out;
 			}
 			add_to_page_cache(page, mapping, idx);
 			unlock_page(page);
-			i_size = (loff_t)(idx + 1) * HPAGE_SIZE;
-			if (i_size > inode->i_size)
-				inode->i_size = i_size;
-
 		}
 		set_huge_pte(mm, vma, page, pte, vma->vm_flags & VM_WRITE);
 	}
diff -Nru a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
--- a/fs/hugetlbfs/inode.c	Thu Oct  9 15:20:21 2003
+++ b/fs/hugetlbfs/inode.c	Thu Oct  9 15:20:21 2003
@@ -139,8 +139,7 @@
 {
 	struct inode *inode = file->f_dentry->d_inode;
 	struct address_space *mapping = inode->i_mapping;
-	struct hugetlbfs_sb_info *sbinfo = HUGETLBFS_SB(inode->i_sb);
-	loff_t len;
+	loff_t len, vma_len;
 	int ret;
 
 	if (vma->vm_start & ~HPAGE_MASK)
@@ -155,17 +154,7 @@
 	if (vma->vm_start < (REGION_HPAGE << REGION_SHIFT))
 		return -EINVAL;
 #endif
-	len = (loff_t)(vma->vm_end - vma->vm_start);
-	if (sbinfo->free_blocks >= 0) { /* Check if there is any size limit. */
-		spin_lock(&sbinfo->stat_lock);
-		if ((len >> HPAGE_SHIFT) <= sbinfo->free_blocks) {
-			sbinfo->free_blocks -= (len >> HPAGE_SHIFT);
-			spin_unlock(&sbinfo->stat_lock);
-		} else {
-			spin_unlock(&sbinfo->stat_lock);
-			return -ENOMEM;
-		}
-	}
+	vma_len = (loff_t)(vma->vm_end - vma->vm_start);
 
 	down(&inode->i_sem);
 
@@ -173,15 +162,11 @@
 	vma->vm_flags |= VM_HUGETLB | VM_RESERVED;
 	vma->vm_ops = &hugetlb_vm_ops;
 	ret = hugetlb_prefault(mapping, vma);
+	len = vma_len + ((loff_t)vma->vm_pgoff << PAGE_SHIFT);
+	if (ret == 0 && inode->i_size < len)
+		inode->i_size = len;
 	up(&inode->i_sem);
 
-	/* If the huge page allocation has failed then increment the free_blocks. */
-	if ((ret != 0) && (sbinfo->free_blocks >= 0)) {
-		spin_lock(&sbinfo->stat_lock);
-		sbinfo->free_blocks += (len >> HPAGE_SHIFT);
-		spin_unlock(&sbinfo->stat_lock);
-	}
-
 	return ret;
 }
 
@@ -261,7 +246,6 @@
 
 void truncate_hugepages(struct inode *inode, struct address_space *mapping, loff_t lstart)
 {
-	struct hugetlbfs_sb_info *sbinfo = HUGETLBFS_SB(mapping->host->i_sb);
 	unsigned long  start = lstart >> HPAGE_SHIFT;
 	unsigned long next;
 	unsigned long max_idx;
@@ -277,13 +261,8 @@
 		page_cache_release(page);
 		truncate_huge_page(mapping, page);
 		unlock_page(page);
-		if (sbinfo->free_blocks >= 0) {
-			spin_lock(&sbinfo->stat_lock);
-			sbinfo->free_blocks ++;
-			spin_unlock(&sbinfo->stat_lock);
-		}
+		hugetlb_put_quota(mapping);
 	}
-
 }
 
 static void hugetlbfs_delete_inode(struct inode *inode)
@@ -717,6 +696,36 @@
 out_dentry:
 	dput(dentry);
 	return ERR_PTR(error);
+}
+
+int hugetlb_get_quota(struct address_space * mapping)
+{
+	int ret = 0;
+	struct hugetlbfs_sb_info *sbinfo =
+		HUGETLBFS_SB(mapping->host->i_sb);
+
+	if (sbinfo->free_blocks > -1) {
+		spin_lock(&sbinfo->stat_lock);
+		if (sbinfo->free_blocks > 0)
+			sbinfo->free_blocks--;
+		else
+			ret = -ENOMEM;
+		spin_unlock(&sbinfo->stat_lock);
+	}
+
+	return ret;
+}
+
+void hugetlb_put_quota(struct address_space *mapping)
+{
+	struct hugetlbfs_sb_info *sbinfo =
+		HUGETLBFS_SB(mapping->host->i_sb);
+
+	if (sbinfo->free_blocks > -1) {
+		spin_lock(&sbinfo->stat_lock);
+		sbinfo->free_blocks++;
+		spin_unlock(&sbinfo->stat_lock);
+	}
 }
 
 static int __init init_hugetlbfs_fs(void)
diff -Nru a/include/linux/hugetlb.h b/include/linux/hugetlb.h
--- a/include/linux/hugetlb.h	Thu Oct  9 15:20:21 2003
+++ b/include/linux/hugetlb.h	Thu Oct  9 15:20:21 2003
@@ -74,6 +74,8 @@
 extern struct file_operations hugetlbfs_file_operations;
 extern struct vm_operations_struct hugetlb_vm_ops;
 struct file *hugetlb_zero_setup(size_t);
+int hugetlb_get_quota(struct address_space *mapping);
+void hugetlb_put_quota(struct address_space *mapping);
 
 static inline int is_file_hugepages(struct file *file)
 {
@@ -89,6 +91,8 @@
 #define is_file_hugepages(file)		0
 #define set_file_hugepages(file)	BUG()
 #define hugetlb_zero_setup(size)	ERR_PTR(-ENOSYS)
+#define hugetlb_get_quota(mapping)	0
+#define hugetlb_put_quota(mapping)	0
 
 #endif /* !CONFIG_HUGETLBFS */